package Both;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;

import Serveur.RechercheTransport;


/**
 * Class descriptif d'un trajet
 * 
 * @author Fabien
 * 
 */
public class Trajet implements Serializable {

    private Ville villeDepart;
    private Ville villeArrive;

    private GregorianCalendar datedepart;
    private GregorianCalendar datearrive;

    private int placeOcupper;

    // Liste des transports
    private Transport transport;

    /**
     * Constructeur normal
     * 
     * @param villeDepart
     * @param villeArrive
     * @param datedepart
     * @param datearrive
     * @param transport
     */
    public Trajet(Ville villeDepart, Ville villeArrive,
            GregorianCalendar datedepart, GregorianCalendar datearrive,
            Transport transport) {
        super();
        this.villeDepart = villeDepart;
        this.villeArrive = villeArrive;
        this.datedepart = datedepart;
        this.datearrive = datearrive;
        this.transport = transport;
        placeOcupper = 0;
    }

    public int getPlaceOcupper() {
        return placeOcupper;
    }

    public GregorianCalendar getDatedepart() {
        return datedepart;
    }

    public GregorianCalendar getDatearrive() {
        return datearrive;
    }

    @Override
    public String toString() {
        String retour;
        retour = "\nVille de depart : " + villeDepart;
        retour += "\nVille d'arrive : " + villeArrive;
        retour += "\nNb place occupe : " + placeOcupper;
        retour += "\nDate arrivé : "
                + displayDate(datearrive.getGregorianChange());
        retour += "\nDate depart : "
                + displayDate(datedepart.getGregorianChange());
        retour += "\nTranport : " + transport.toString();
        retour += "\n";

        return retour;
    }

    public String displayDate(Date d) {
        return (d.getYear() + "-" + d.getMonth() + "-" + d.getDay() + " "
                + d.getHours() + ":" + d.getMinutes());
    }

    public Ville getVilleDepart() {
        return villeDepart;
    }

    public Ville getVilleArrive() {
        return villeArrive;
    }

    public void print() {
        System.out.println(toString());
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        Trajet t = new Trajet(this.villeDepart, this.villeArrive,
                this.datedepart, this.datearrive, this.transport);
        return t;
    }

    public Transport getTransport() {
        return transport;
    }

    /**
     * Verifier si le nombre de place est assez importante pour reserver un
     * certain nombre de personne
     * 
     * @param nbPlace
     * @return
     */
    public boolean peutReserver(int nbPlace) {
        if ((placeOcupper + nbPlace) <= transport.getCapacite()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Reserver le bombre de palce demand�, il faut augmenter le nombre de place
     * occup�.
     * 
     * @param nbplace
     * @return
     */
    public boolean reserver(int nbplace) {
        if (peutReserver(nbplace)) {
            placeOcupper += nbplace;
            return true;
        } else {
            return false;
        }
    }

    /**
     * Enlever le nombre de passag� reserv�
     * 
     * @param nb
     * @return
     */
    public boolean annulerReservation(int nb) {
        if (nb < 0) {
            return false;
        }

        if ((placeOcupper - nb) < 0) {
            return false;
        }

        placeOcupper = placeOcupper - nb;
        return true;
    }

    /**
     * Recuperer le nombre de place dispo
     * 
     * @return the nomber of free place
     */
    public int getNbPlaceDispo() {
        int capacite = transport.getCapacite();
        return capacite - placeOcupper;
    }

    /**
     * Recherche de trajet par ville, par date et par transport et selon les
     * places disponibles
     * 
     * @param ListeTrajetsarg
     * @param villeDepart
     * @param villeArrive
     * @param dateDepart
     * @param dateArrive
     * @param t
     * @return
     */
    public static ArrayList<Trajet> searchTrajet(
            ArrayList<Trajet> ListeTrajetsarg, Ville villeDepart,
            Ville villeArrive, GregorianCalendar dateDepart,
            GregorianCalendar dateArrive, Transport t, int nbPersonne) {
        ArrayList<Trajet> ListeTrajetRetour = (ArrayList<Trajet>) ListeTrajetsarg
                .clone();

        // Verifier que la liste des trajets n'est pas nulle
        if (ListeTrajetsarg == null) {
            return null;
        }

        // Si la ville de depart n'est pas null
        if (villeDepart != null) {
            Iterator<Trajet> it = ListeTrajetsarg.iterator();
            while (it.hasNext()) {
                Trajet current = it.next();
                if (!current.getVilleDepart().equals(villeDepart)) {
                    ListeTrajetRetour.remove(current);
                }
            }
        }

        // Si la ville de depart n'est pas null
        if (villeArrive != null) {
            Iterator<Trajet> it = ListeTrajetsarg.iterator();
            while (it.hasNext()) {
                Trajet current = it.next();
                if (!current.getVilleArrive().equals(villeArrive)) {
                    ListeTrajetRetour.remove(current);
                }
            }
        }

        // Si la ville de depart n'est pas null
        if (dateDepart != null) {
            Iterator<Trajet> it = ListeTrajetsarg.iterator();
            while (it.hasNext()) {
                Trajet current = it.next();
                if (!current.getDatedepart().equals(dateDepart)) {
                    ListeTrajetRetour.remove(current);
                }
            }
        }

        // Si la ville de depart n'est pas null
        if (dateArrive != null) {
            Iterator<Trajet> it = ListeTrajetsarg.iterator();
            while (it.hasNext()) {
                Trajet current = it.next();
                if (!current.getDatearrive().equals(dateArrive)) {
                    ListeTrajetRetour.remove(current);
                }
            }
        }

        // Si la ville de depart n'est pas null
        if (t != null) {
            Iterator<Trajet> it = ListeTrajetsarg.iterator();
            while (it.hasNext()) {
                Trajet current = it.next();
                if (!current.getTransport().equals(t)) {
                    ListeTrajetRetour.remove(current);
                }
            }
        }

        if (nbPersonne > 0) {
            Iterator<Trajet> it = ListeTrajetsarg.iterator();
            while (it.hasNext()) {
                Trajet current = it.next();
                if (!current.peutReserver(nbPersonne)) {
                    // Supprimer les trajets dans lesquels il n'y � plus de
                    // place diponible.
                    ListeTrajetRetour.remove(current);
                }
            }
        }

        // Rechercher dans les trajets
        if (ListeTrajetsarg.size() == ListeTrajetRetour.size()
                && villeArrive != null && villeDepart != null) {
            ArrayList<Trajet> ListeMod = (ArrayList<Trajet>) ListeTrajetsarg
                    .clone();
            RechercheTransport rech;
            try {
                rech = new RechercheTransport(villeDepart, villeArrive,
                        ListeMod);
            } catch (IllegalArgumentException e) {
                return null;
            }
            if (rech.cheminPossible()) {
                return rech.Chemin();
            }
        }

        return ListeTrajetRetour;
    }

    /**
     * Recuperer le temps necessaire pour effectuer le trajet
     * 
     * @return the time for travel
     */
    public int getTime() {
        int h1 = ((datearrive.getGregorianChange().getHours()) * 60)
                + ((datearrive.getGregorianChange().getMinutes()));
        int h2 = (datedepart.getGregorianChange().getHours()) * 60
                + ((datedepart.getGregorianChange().getMinutes()));
        return h1 - h2;
    }
    
    /**
     * Redefinition de la methode equals
     */
    @Override
    public boolean equals(Object obj) {
    	if(obj == null){
    		return false;
    	}
    	
        Trajet t = (Trajet)obj;
        if(!t.getDatearrive().equals(this.getDatearrive())){
            return false;
        }
        if(!t.getDatedepart().equals(this.getDatedepart())){
            return false;
        }
        if(!(t.getNbPlaceDispo() == (this.getNbPlaceDispo()))){
            return false;
        }
        if(!t.getTransport().equals(this.getTransport())){
            return false;
        }
        if(!t.getVilleArrive().equals(this.getVilleArrive())){
            return false;
        }
        if(!t.getVilleDepart().equals(this.getVilleDepart())){
            return false;
        }
        return true;
    }
}
